package com.saturday.web.exception;

import com.saturday.common.exception.BusinessException;
import com.saturday.common.exception.UserContextLoseException;
import com.saturday.common.util.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Configuration
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    public Object defaultErrorHandler(Exception e) throws Exception {
        log.error("系统异常：{}", e);
        return ResultUtils.error("系统异常", String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
    }


    /**
     * 处理运行时异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(value = RuntimeException.class)
    public Object runtimeException(RuntimeException ex) {
        log.error("系统异常：{}", ex);
        return ResultUtils.error("系统异常！", String.valueOf(HttpStatus.EXPECTATION_FAILED.value()));
    }

    /**
     * 处理自定义业务异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(value = BusinessException.class)
    public Object exceptionHandler(BusinessException ex) {
        log.error("业务异常详情:{}", ex);
        return ResultUtils.error(ex.getMessage(), ex.getCode());
    }


    @ExceptionHandler(value = UserContextLoseException.class)
    public Object notLoginException(UserContextLoseException e) {
        log.error("当前用户信息不存在异常：{}", e);
        return ResultUtils.notLogin();
    }

    /**
     * 方法入参校验异常处理 content-type!=application/json
     *
     * @param ex 异常
     * @return Object
     */
    @ExceptionHandler({BindException.class})
    public Object bindExceptionException(BindException ex) {
        List<String> validResult = ex.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());
        log.warn("参数非法：{}", ex);
        return ResultUtils.error(validResult.get(0));
    }

    /**
     * 方法入参校验异常处理 content-type=application/json
     *
     * @param ex 异常
     * @return Object
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Object methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        List<String> validResult = ex.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());
        log.warn("参数非法：{}", ex);
        return ResultUtils.error(validResult.get(0));
    }

    /**
     * 请求类型不支持
     *
     * @param httpRequestMethodNotSupportedException
     * @return
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public Object handleNotSupportedHttpMethodException(HttpRequestMethodNotSupportedException httpRequestMethodNotSupportedException) {
        log.error("HttpRequestMethodNotSupportedException：{}", httpRequestMethodNotSupportedException);
        return ResultUtils.error(httpRequestMethodNotSupportedException.getMessage(), String.valueOf(HttpStatus.EXPECTATION_FAILED.value()));
    }

    /**
     * media type not support
     *
     * @param httpMediaTypeNotSupportedException
     * @return
     */
    @ExceptionHandler(value = HttpMediaTypeNotSupportedException.class)
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public Object handleNotSupportedHttpMethodException(HttpMediaTypeNotSupportedException httpMediaTypeNotSupportedException) {
        log.error("HttpMediaTypeNotSupportedException：{}", httpMediaTypeNotSupportedException);
        return ResultUtils.error(httpMediaTypeNotSupportedException.getMessage(), String.valueOf(HttpStatus.EXPECTATION_FAILED.value()));
    }
}
